﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using CommonLibraries.DeviceLibrary.Helpers;

namespace CommonLibraries.DeviceLibrary
{
    public class GPS : IGPS, IDisposable
    {
        private static GPS Instance = null;
        private bool m_HasSolution = false;
        /// <summary>
        /// Holds the access to the serial port
        /// </summary>
        SerialPortMonitor m_SerialPortMonitor = null;
        bool m_DisposeOfSerialPortMonitor = true;

        public void ChangeToMode (ReceptionMode mode)
        {
            m_SerialPortMonitor.ChangeToMode(mode);
        }

        /// <summary>
        /// Constructor - allows the reuse of an single instance of SerialPortMonitor
        /// </summary>
        public GPS(SerialPortMonitor serialPortMonitor)
        {
            try
            {
                m_DisposeOfSerialPortMonitor = false;
                m_SerialPortMonitor = serialPortMonitor;
                m_SerialPortMonitor.Open();
                m_SerialPortMonitor.WriteLine(SerialPortMonitor.GrilMessages.StartGPGGA);
                m_SerialPortMonitor.ReceivedNmeaGGA += new EventHandler<CommonLibraries.ProjectCommon.EventArgs<NmeaGGA>>(m_SerialPortMonitor_ReceivedNmeaGGA);
            }
            catch (Exception ex)
            {
                CreateDebug("GPS->Serialmonitor" + ex.Message);
            }

        }
        
        private static void CreateInstance()
        {
            if (Instance == null)
            {
                Instance = new GPS();
            }
        }

        public static GPS GetInstance()
        {
            if (Instance == null) CreateInstance();
            return Instance;
        }


        /// <summary>
        /// Constructor
        /// </summary>
        private GPS()
        {
            try
            {
                m_SerialPortMonitor = new SerialPortMonitor();
                m_SerialPortMonitor.Open();
                m_SerialPortMonitor.WriteLine(SerialPortMonitor.GrilMessages.StartGPGGA);
                m_SerialPortMonitor.ReceivedNmeaGGA += new EventHandler<CommonLibraries.ProjectCommon.EventArgs<NmeaGGA>>(m_SerialPortMonitor_ReceivedNmeaGGA);

            }
            catch (Exception ex)
            {
                CreateDebug("GPS-> " +ex.Message);
            }
        }

        /// <summary>
        /// Fires when the serial port receives expected data
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void m_SerialPortMonitor_ReceivedNmeaGGA(object sender, CommonLibraries.ProjectCommon.EventArgs<NmeaGGA> e)
        {
            //try
            //{
            //    NmeaGGA = e.Value;

            //    // raise event(s)


            //    if (NmeaGGA.Quality > 0)
            //    {

            //        if (this.PositionReceived != null)
            //            this.PositionReceived(this, new EventArgs());

            //        if (this.HasSolution && this.HasSolutionChanged != null)
            //            this.HasSolutionChanged(this, new EventArgs());
            //    }
            //    else
            //    {
            //        if (this.HasSolutionChanged != null)
            //            this.HasSolutionChanged(this, new EventArgs());

            //    }
            //}
            //catch (Exception ex)
            //{
            //    CreateDebug("m_SerialPortMonitor_ReceivedNmeaGGA -> " + ex.Message);
            //    //Reset();
            //}

            this.NmeaGGA = e.Value;

            //if this.HasSolutionChanged has subscribe events  
            if(this.HasSolutionChanged != null)
            {
                m_HasSolution = NmeaGGA.HasSolution;
                this.HasSolutionChanged(this, new EventArgs());
                //ErrorManager.CreateDebug("Log.txt", "GPS.m_SerialPortMonitor_ReceivedNmeaGGA.Altitude -> " + e.Value.Altitude);
                //ErrorManager.CreateDebug("Log.txt", "GPS.m_SerialPortMonitor_ReceivedNmeaGGA.Longitude -> " + e.Value.Longitude);
                //ErrorManager.CreateDebug("Log.txt", "GPS.m_SerialPortMonitor_ReceivedNmeaGGA.Quality -> " + e.Value.Quality);
                
                ////If solution has changed then raise it
                //if (m_HasSolution != NmeaGGA.HasSolution)
                //{
                //    m_HasSolution = NmeaGGA.HasSolution;
                //    this.HasSolutionChanged(this, new EventArgs());
                //}
            }

            //if this.PositionReceived has subscribe events  
            if(this.PositionReceived != null)
            {
                //If a position is recived correctly
                if(this.NmeaGGA.Quality > 0)
                    this.PositionReceived(this, new EventArgs());
            }
            
        }

        #region IGPS Members

        public event EventHandler HasSolutionChanged;
        public event EventHandler PositionReceived;
        public event EventHandler PowerStateChanged;

        private NmeaGGA prop_NmeaGGA;
        public NmeaGGA NmeaGGA
        {
            get
            {
                return prop_NmeaGGA;
            }
            set
            {
                prop_NmeaGGA = value;
            }
        }

        public PowerStates PowerState
        {
            get
            {
                int _powerstate;
                _powerstate = TGMS2.TGMS2_GetGpsPowerState();
                return (_powerstate != 0 ? PowerStates.On : PowerStates.Off);
            }
            set
            {
                PowerStates _OriginalPowerState;
                _OriginalPowerState = this.PowerState;

                int _powerstate;
                _powerstate = (value == PowerStates.On ? 1 : 0);
                TGMS2.TGMS2_SetGpsPowerState((int)_powerstate);

                if ((int)_OriginalPowerState != _powerstate && PowerStateChanged != null)
                    PowerStateChanged(this, new EventArgs());
            }
        }

        /// <summary>
        /// Based on pre-set Quality indicators (1,2,3,4 only)
        /// </summary>
        public bool HasSolution
        {
            get
            {
                try
                {
                    return m_HasSolution;
                }
                catch (Exception)
                {
                    return false;
                }
            }
        }

        public int SerialNumber
        {
            get
            {
                byte _SerialNumber = new byte();
                TGMS2.TGMS2_GetSerialNumber(_SerialNumber);
                return _SerialNumber;
            }
        }

        public void Reset()
        {
            
            try
            {
                Dispose();
                m_SerialPortMonitor = new SerialPortMonitor();
                m_SerialPortMonitor.Open();
                m_SerialPortMonitor.WriteLine(SerialPortMonitor.GrilMessages.StartGPGGA);
                m_SerialPortMonitor.ReceivedNmeaGGA += new EventHandler<CommonLibraries.ProjectCommon.EventArgs<NmeaGGA>>(m_SerialPortMonitor_ReceivedNmeaGGA);

            }
            catch (Exception ex)
            {
                CreateDebug("GPS-> " + ex.Message);
            }

        }


        public void Stop()
        {

            try
            {
                m_SerialPortMonitor.WriteLine(SerialPortMonitor.GrilMessages.StopAll);
                m_SerialPortMonitor.ReceivedNmeaGGA -= new EventHandler<CommonLibraries.ProjectCommon.EventArgs<NmeaGGA>>(m_SerialPortMonitor_ReceivedNmeaGGA);

            }
            catch (Exception ex)
            {
                CreateDebug("GPS-> " + ex.Message);
            }

        }

        public void Restart()
        {

            try
            {
                m_SerialPortMonitor.WriteLine(SerialPortMonitor.GrilMessages.StartGPGGA);
                m_SerialPortMonitor.ReceivedNmeaGGA += new EventHandler<CommonLibraries.ProjectCommon.EventArgs<NmeaGGA>>(m_SerialPortMonitor_ReceivedNmeaGGA);

            }
            catch (Exception ex)
            {
                CreateDebug("GPS-> " + ex.Message);
            }

        }


        #endregion

        #region IDisposable Members

        /// <summary>
        /// Ensure the underlying serial port is closed
        /// </summary>
        public void Dispose()
        {
            m_SerialPortMonitor.ReceivedNmeaGGA -= new EventHandler<CommonLibraries.ProjectCommon.EventArgs<NmeaGGA>>(m_SerialPortMonitor_ReceivedNmeaGGA);
            if(m_DisposeOfSerialPortMonitor)
                m_SerialPortMonitor.Dispose();
        }

        #endregion


        protected void CreateDebug(string debugData)
        {
            StreamWriter _a = File.AppendText(".\\DebugClasses.txt");
            _a.WriteLine("##############################");
            _a.WriteLine(System.DateTime.Now.ToShortDateString() + " " + System.DateTime.Now.ToShortTimeString());
            _a.WriteLine("##############################");
            _a.WriteLine(debugData);
            _a.Close();
            _a.Dispose();

        }

    }
}
